<?php
/**
 * Name: cartnew.php
 * Desc: This class is designed to provide a basic, extendable framework for an eCommerce backend.
 *
 * Version: 1.5
 *
 * Date:    (Revised) May 30, 2007 and many more
 * Author:  Christopher J. Burdick
 **/

require_once('db.class.php');

if (!isset($_SESSION)) {
	if (!isset($SITEROOT)) $SITEROOT = '../../../';
	require_once($SITEROOT . 'manager/includes/config.inc.php');
	startCMSSession();
}

class Kiwee {
	public $config = array();
	public $db;
	
	function __construct(){
		// Connect to the database		
		$this->db = new db();

		// Just in case we change the name again =)
		// Stores the prefix of the ecommerce tables
		$this->loadConfig();
	}
	
/**
 * loadConfig will load the config options from the database
 **/
	private function loadConfig(){
		$this->config['pfx'] = 'modx_';
		$this->config['fpx'] = 'modx_kiwee_';
		$this->config['ecp'] = 'kiwee_';
		// Grab Config Data
		$result = $this->db->sel($this->config['fpx'], 'config_values', 'optname, optval');
		$row = $result;
		// Load Config Array
		for ($i=0; $i < sizeof($row); $i++){
			$this->config[$row[$i]['optname']] = $row[$i]['optval'];
		}
		// Added two params that I don't want people to have direct access to as they are only used for changing
		// the table prefix for the ecommerce tables.  It is mostly used for testing with older versions of 
		// Kiwee.
	}
	
/**
 * unloadConfig will unload the config options from memory
 **/
	
	private function unloadConfig(){
		$this->config=array();	
	}
	
/**
 * reloadConfig will just call out to unloadConfig followed by loadConfig to recreate the
 * config database in case this has to be done on the fly for a particular method...perhaps
 * when new config options are created dynamically or if we modify existing config options.
 **/
	
	public function reloadConfig(){
		$this->unloadConfig();
		$this->loadConfig();
	}
	
/**
 * This function is designed to create a shopping cart.  Without any items, the shopping cart is simply
 * an entry in kiwee_cart_header
 * 
 * @param sessionid		- The Session ID of the user whose cart we are creating
 * 
 * @return the id and session_id that were added to the database
 **/
    public function createCart($sessionid){
		$result = $this->db->sel($this->config['fpx'], 'cart_header', 'id, datemodified, subtotal, itemsincart, session_id', 'session_id="' . $sessionid . '"');
		if (sizeof($result) > 0){
	        $headerinfo = $result[0];
		} else {
			$headerinfo = "";
		}
		
        $dat = date("D M j G:i:s T Y");

        if ($sessionid != $headerinfo['session_id']){
            $this->db->ins($this->config['fpx'], 'cart_header',  'session_id, dateadded', '"' . $sessionid . '","' . $dat . '"');
            $result=$this->db->sel($this->config['fpx'], 'cart_header', 'id, session_id', 'session_id="' . $sessionid . '"');
            $headerinfo = $result[0];
        }
        return $headerinfo;
    }
	
/**
 * This function will take in a contentid and return the mySQL id of an item.
 * 
 * @param	contentid		=	The MODx content id (mysql id of the page which the item resides on)
 * 
 * @return	The MySQL id of the item
 **/
	public function getItemId($contentid){
		$result = $this->db->sel($this->config['fpx'], 'items', 'id', 'content_id=' . $contentid);

		return $result[0]['id'];
	}
	
/**
 * This function is designed to obtain or create a cart header, and then add a new entry to the detail
 * table for the item that the user added to their cart.
 * 
 * @param	id			=	mySQL ID of the item 
 * @param	sessionid	=	Session ID of the user
 * @param 	opts		= 	Associative array of the options chosen when the item was added
 * @param	qty			=	Item Quantity
 * 
 * @return	A string which displays the number of items in the cart with a link to view the cart.  																																																																																																																									   *$HE																																																																																																																			   * NOTE: This may be a config variable in the future
 **/
																																																																																																																										 
	public function addToCart($id, $sessionid, $opts, $qty){
        $qty = $qty > 0 ? $qty : 1;
        $hdrinfo = $this->createCart($sessionid);

        // Check to make sure cart was created
		
        $dat = date("D M j G:i:s T Y");

        $itincart = intval($hdrinfo['itemsincart']);

        // Get options pricing
        $optionsreturn = $this->getOptionsPricing($opts, $id, $qty);
        $result = $this->db->sel($this->config['fpx'], 'items', 'amount', 'id=' . $id);
        $item = $result[0];

        if (isset($id)){
            $result = $this->db->sel($this->config['fpx'], 'cart_detail', 'id,quantity,options,optionsprice,totalprice','header_id=' . $hdrinfo['id'] . ' AND item_id=' . $id);

            $flag=false;
            $num = sizeof($result);
            for ($k=0; $k < $num; $k++){
                $res = $result[$k];
                if ($res['options']==$optionsreturn['optstring']){
                    $itincart = $itincart + $qty;
                    $quantity = $res['quantity'] + $qty;
                    $prc = floatval($item['amount']);
											
                    $newprc=floatval($hdrinfo['subtotal']) + ($prc * $qty) + floatval($optionsreturn['price']);
				
                    $optsprice=floatval($res['optionsprice']) + floatval($optionsreturn['price']);
                    $totalprice = floatval($res['totalprice']) + (floatval($prc) * $qty) + floatval($optionsreturn['price']);
                    $this->db->upd($this->config['fpx'], 'cart_detail', 'quantity=' . $quantity . ', optionsprice=' . $optsprice . ', totalprice=' . $totalprice, 'header_id=' . $hdrinfo['id'] . ' AND id=' . $res['id']);
                    $this->db->upd($this->config['fpx'], 'cart_header', 'datemodified="' . $dat . '", itemsincart=' . $itincart . ', subtotal=' . $newprc, 'id=' . $hdrinfo['id']);
					$flag=true;
                }
           }
										
            if ($flag==false){
				// In case there was already one in the cart but the options were NOT equal...add new record
                $itincart= $itincart + $qty;
                $result = $this->db->sel($this->config['fpx'], 'items', 'amount', 'id=' . $id);
                $item = $result[0];
                $prc = floatval($item['amount']);
                $totalprice = (floatval($prc) * $qty) + floatval($optionsreturn['price']);
                $newprc = floatval($hdrinfo['subtotal']) + ($prc * $qty) + floatval($optionsreturn['price']);
                $this->db->upd($this->config['fpx'], 'cart_header', 'datemodified="' . $dat . '", itemsincart=' . $itincart . ', subtotal=' . $newprc, 'id=' . $hdrinfo['id']);
				$this->db->ins($this->config['fpx'], 'cart_detail', 'header_id, item_id, quantity, date, options, optionsprice, totalprice', $hdrinfo['id'] . ', ' . $id . ', ' . $qty . ', "' . $dat . '", "' . addslashes($optionsreturn['optstring']) . '", ' . floatval($optionsreturn['price']) . ', ' . $totalprice);
                $result = $this->db->sel($this->config['fpx'], 'cart_detail', 'id', 'header_id=' . $hdrinfo['id'] . ' AND item_id=' . $id);
                $detail_id = $result[0];
            }
         }
				
        $quant = $this->getItemCount($sessionid);
        $cartNotifier= isset($quant) ? 'You have ' . $quant : 'You have 0 items in your shopping Cart!';
				
        if ($quant > 1) {
	        $cartNotifier .= ' items in your shopping cart totaling: $' . floatval($newprc);
        }  else if ($quant == 1) {
            $cartNotifier .= ' item in your shopping cart totaling: $' . floatval($newprc);
        }
				
        $cartNotifier .= '<br />';
        $cartNotifier .= '<a href="index.php?id=' . $this->config['cart_additempage'] . '&sessionid=' . $sessionid . '">View Cart</a>';
				
        return $cartNotifier;				
	}
		
/**
 * This function is designed to take an encoded string of the options that a user passes when their item is added to the cart and figure the item's price
 * appropriately.
 * 
 * @param	opts	=	Encoded string of the options selected on the website
 * @param	id		=	ID of the item we are adding (MySQL ID)
 * @param	qty		=	Qty, so we can figure out the total options pricing (not just for qty=1)\
 * 
 * @return 	An array with the options selected and their pricing
 **/
	private function getOptionsPricing($opts, $id, $qty){
        // Init Vars
        $ret['price'] = 0;
        $ret['optstring'] = '';
		
        // Break opts passed from site into an array
        $splitopts = explode("||||", $opts);
		
        for ($i=0; $i < sizeof($splitopts); $i++){
					
			//Split name of option from value
      		$splitnameval=explode('::::', $splitopts[$i]);
		
        	// Store Option Name
        	$optsfromsite[$i][0] = $splitnameval[0];
		
        	// Store value(s) chosen by customer
        	$optsfromsite[$i][1] = $splitnameval[1];
		
        	// Get Option Render just so we know what to do to get all values and what to return to the user.
        	$optinfo = $this->getOptionByName($optsfromsite[$i][0]);
		
            /** 
		  	 * It is important to check, as we don't want to obtain options from a TEXT
         	 * or TEXT Area and we only need to loop through multiple options for
         	 * a CHECK or SELECT
         	 **/
            if ($optinfo['renderas']=='CHECK' || $optinfo['renderas']=='MULTI'){
	 	      	// checkbox and multi selects send info as id;;;;id;;;;id;;;; etc...
               	$optsvalsplit=explode(';;;;', $optsfromsite[$i][1]);
               	$flag = false;
               	$first = true;
				
               	for ($j=0; $j < sizeof($optsvalsplit); $j++){
	            	//Just in case they choose no options
                   	if ($optsvalsplit[$j]!=""){
	                	$optproperties = $this->getListOptionProperties($optsvalsplit[$j]);
                       	$ret['price'] = $ret['price'] + (floatval($optproperties['offset']) * $qty);
                       	if ($first==true){
	                    	$optsvalname=$this->getListOptionProperties($optsvalsplit[$j]);
                           	$ret['optstring'] .= $optsfromsite[$i][0] . ': ' . $optsvalname['name'];
                           	$first=false;
                       	} else {
 	                    	$optsvalname=$this->getListOptionProperties($optsvalsplit[$j]);
                          	$ret['optstring'] .= ', ' . $optsvalname['name'];
                       	}
                        $flag=true;
                    } else {
 	                   if ($flag==false){
	                       $ret['optstring'] .= $optsfromsite[$i][0] . ': None';
                       }
                    }
                }
                $ret['optstring'] .= '<br />';
            } else if ($optinfo['renderas']=='SELECT' || $optinfo['renderas']=='RADIO'){
				 echo "TESTTEST: " . $optsfromsite[$i][1];
	             $optproperties = $this->getListOptionProperties($optsfromsite[$i][1]);
                 $ret['price'] = $ret['price'] + (floatval($optproperties['offset']) * $qty);
				 $ret['optstring'] .= $optsfromsite[$i][0] . ": " . $optproperties['name'] . '<br />';
			} else if ($optinfo['renderas']=='TEXT' || $optinfo['renderas']=='TEXTAREA'){
				 $ret['optstring'] .= $optsfromsite[$i][0] . ": " . $optsfromsite[$i][1] . '<br />';
			}
        }
		return $ret;		
	}
		
/**
 * This function is designed to handle loading the data for a particular item from the audit table.
 * 
 * @param id	=	itemid
 **/
	public function getItemProperties($id){
        $result = $this->db->sel($this->config['fpx'], 'items_audit', 'id, content_id, sku, name, fullname, description, amount, oversized, hazmat, disabled, shoppingenabled, quoteenabled, status', 'id=' . $id);
        $row = $result[0];

        $itemprops['id'] = $row['id'];
        $itemprops['content_id'] = $row['content_id'];
        $itemprops['sku'] = $row['sku'];
        $itemprops['name'] = $row['name'];
        $itemprops['fullname'] = $row['fullname'];
        $itemprops['amount'] = $row['amount'];
        $itemprops['oversized'] = $row['oversized'];
        $itemprops['hazmat'] = $row['hazmat'];
        $itemprops['disabled'] = $row['disabled']==0 ? 'ENABLED' : 'DISABLED';;
        $itemprops['shoppingenabled'] = $row['shoppingenabled']==0 ? 'DISABLED' : 'ENABLED';
        $itemprops['quoteenabled'] = $row['quoteenabled']==0 ? 'DISABLED' : 'ENABLED';
        $itemprops['status'] = $row['status'];		

        $result = $this->db->sel($this->config['pfx'], 'site_content', 'template, content, longtitle, description', 'id="' . $itemprops['content_id'] . '"');
        $row = $result[0];
	
        $itemprops['pagetemplate'] = $row['template'];
        $itemprops['contentarea'] =  $row['content'];
        $itemprops['longtitle'] = $row['longtitle'];
        $itemprops['description'] = $row['description'];		
		
		return $itemprops;
	}
		
/**
 * This function is designed to handle updating an items options in items_options
 *
 * @param		itemid		=	The ID (MySQL) of the item to update
 * @param		chosenopts	=	The ID's of the chosen options for an item
 **/
	public function updateItemOptions($itemid, $chosenopts){
		// Delete all options first that are already associated with the item
		$this->db->del($this->config['fpx'], 'items_options', 'item_id=' . $itemid);
		
		// Read new options
		for ($i=0; $i < sizeof($chosenopts); $i++){
			$this->db->ins($this->config['fpx'], 'items_options', 'options_id, item_id', $chosenopts[$i] . ', ' . $itemid);	
		}
	}
		
/**
 * This function is designed to handle item page updates.  If the ID is 0, it is new...if the ID is > 0 it means the page is being updated
 *
 * @param   itemid              = MySQL ID of the item to be edited  (NOTE:  if 0, it indicates that the item is new)
 * @param   itemname            = Name of the Item
 * @param   shortdescription    = Longer description of the item (but still short)
 * @param   contentarea         = The main templated content area
 * @param   price               = Price of the Item
 * @param   hazmat              = Hazmat fee for shipping
 * @param   oversized           = Oversized shipping fee
 * @param   status              = Audit Status =>  Whether the item is updated, new, etc.  This is mostly for use by Blackbird...our open source ESB offering
 *                                for QuickBooks integration
 * @param   active              = Tells whether the item is active or inactive
 * @param   enablequote         = Is the quote basket enabled?
 * @param   template            = Overall page template
 * @param   enableshop          = Is the Shopping Cart enabled for this item?
 **/
	public function updatePage($itemid, $itemname, $shortdescription, $contentarea, $price, $hazmat, $oversized, $status, $active, $enablequote, $template, $enableshop){
		// Convert Booleans to binary
		if ($enableshop=='true'){$enableshop = 1;}else{$enableshop = 0;}
		if ($enablequote=='true'){$enablequote = 1;}else{$enablequote = 0;}
		if ($active=='true'){$active= 0;}else{$active=1;}
		
		if ($itemid == 0){ // New Item
			$itemid = $this->writeItemToDB($itemid, $itemname, $shortdescription, $price, $hazmat, $oversized, $enableshop, $enablequote, $active, 'NEW');
		
			//Config - Probably shouldn't touch too much here...perhaps changing a template
			$parent= 4008;
			$richtext= 1;
			$searchable= 1;
			$cacheable= 0;
			$published= 1;	
			$contentid = $this->addContainer($itemid, $itemid, $contentarea, $itemname, $shortdescription, $shortdescription, $published, $parent, $richtext, $template, $searchable, $cacheable, $itemname);
        	// add container id to the item in the database (for easy update and retrieval of the correct site content
        	$this->db->upd($this->config['fpx'], 'items', 'content_id=' . $contentid, 'id=' . $itemid);
        	$this->db->upd($this->config['fpx'], 'items_audit', 'content_id=' . $contentid, 'items_id=' . $itemid);
        }else { // Updated Item
			$itemid = $this->writeItemToDB($itemid, $itemname, $shortdescription, $price, $hazmat, $oversized, $enableshop, $enablequote, $active, 'UPDATED');
            $result  = $this->db->sel($this->config['fpx'], 'items_audit', 'content_id' , 'items_id=' . $itemid);
            $row = $result[0];
            $contentid = $row['content_id'];

            //Update Container Page
			$this->db->upd($this->config['pfx'], 'site_content', 'pagetitle="' . $itemname . '", longtitle="' . $itemname . '", description="' . $shortdescription . '", template=' . $template . ', content="' . $contentarea . '", menutitle="' . $itemname . '"','id=' . $contentid);
		}
	}
		
/**
 * This function is used for updating an item already in a cart.  If the quantity is set to zero it will delete the item,
 * otherwise it will update the item record from the cart.
 * 
 * @param      sku             =   SKU of the item
 * @param      sessionid       =   Session ID of the user
 * @param      qty             =   Item Quantity
 * @param      opts            =   Options which were chosen with the item
 * @param      detailid        =   The detailid is included to make sure we delete or update the correct item from the user's cart
 **/
	public function updateItem($sessionid, $sku, $qty, $opts, $detailid){
		$result = $this->db->sel($this->config['fpx'], 'cart_header', 'id', 'session_id="' . $sessionid . '"');
		$header_id = $result[0];
		
		$result = $this->db->sel($this->config['fpx'], 'items', 'id', 'sku="' . $sku . '"');
		$item_id = $result[0];
		
		$options = encodeOptions($opts, $item_id['id']);
		
		$dat = date("D M j G:i:s T Y");
		
		if ($qty==0){
			$this->db->del($this->config['fpx'], 'cart_detail', 'header_id="' . $header_id['id'] . '" AND item_id="' . $item_id['id'] . '" AND id=' . $detailid);
		} else {
			$this->db->upd($this->config['fpx'], 'cart_detail', 'quantity=' . $qty . ', date="' . $dat. '", options="' . $opts['options'] . '", optionsprice=' . floatval($opts['price']), 'id=' . $detailid . ' AND item_id=' . $item_id);	
		}
	}
	
/**
 *  This function is used if you want to delete an item without passing me a quantity of zero.  If you're using this you might be considered lazy.
 *  Just pass me your session id and item number and I guess I'll take care of it.
 *
 *  @param      sessionid       =   Session ID of the user
 *  @param      detailid        =   This is the id of the detail line to delete
 **/
    function deleteItem($sessionid, $itemid){
        $result = $this->db->sel($this->config['fpx'], 'cart_header', 'id, datemodified, itemsincart, subtotal', 'session_id="' . $sessionid . '"');
        $headrec = $result[0];

        $result = $this->db->sel($this->config['fpx'], 'cart_detail', 'quantity, totalprice', 'header_id=' . $headrec['id'] . ' AND id=' . $itemid);
        $record = $result[0];

        $subtotal = floatval($headrec['subtotal']) - floatval($record['totalprice']);
        $itemsincart = floatval($headrec['itemsincart']) - floatval($record['quantity']);
		if ($itemsincart < 0){
			$itemsincart=0;	
		}
        $datemodified = date("D M j G:i:s T Y");
	
        $this->db->del($this->config['fpx'], 'cart_detail', 'header_id=' . $headrec['id'] . ' AND id=' . $itemid);
        $this->db->upd($this->config['fpx'], 'cart_header', 'subtotal=' . $subtotal . ', itemsincart=' . $itemsincart . ', datemodified="' . $datemodified . '"', 'id=' . $headrec['id']);
    }
	
		
/**
 * This function is used for encoding the options string.  This will return an array containing the options string and the optionsvalue
 * 
 * @param		opts	=	This is an of the names of the options which were selected for an item.
 * @param		item_id	=	This is the ID (MySQL) of the item.
 **/
	public function encodeOptions($opts, $item_id){
		$price = 0;
		
		foreach($opts as $var => $value){
			$option = $this->getOption($item_id, $var);
			$listitem = $this->getListOption($option['listid']);
			$price = $price + (floatval($listitem['priceoffset']));
			$options = $options + $listitem['name'] + ':' + $value + ';';
		}
		
		$arr['options'] = $options;
		$arr['price'] = $price;
		return $arr;
	}
		
/**
 * This function is designed as a gateway to process various types of checkouts.
 * It's only purpose is to redirect to the appropriate handler for the checkout
 * method chosen during the checkout process.
 **/
	public function processCheckout($sessionid, $paymethod, $cardtype, $nameoncard, $cardnum, $routenum, $cvvcode, $expmo, $expyr){
        switch ($paymethod){
	        // Credit Line offered by Merchant
            case "CREDIT":
//                return "MADE IT CREDIT";
            break;
            // Mail a Check
            case "CHECK":
//                return "MADE IT CHECK";
            break;
            // Process a credit card with authorize.NET
            case "CREDITCARD":
                $headerid= $this->convertToOrder($sessionid);
			
				$cc['cardtype'] = $cardtype;
			    $cc['nameoncard'] = $nameoncard;
			    $cc['cardnum'] = $cardnum;
			    $cc['cvvcode'] = $cvvcode;
			    $cc['expmo'] = $expmo;
			    $cc['expyr'] = $expyr;
                $response= $this->processCC($cc);
            break;
            // Process an eCheck with authorize.NET (not yet implemented)
            case "ECHECK":
//                return "MADE IT ECHECK";
            break;
            // Add order from a google Checkout (Google takes care of the rest)
            case "GOOGLE":
//                return "MADE IT GOOGLE";
            break;
            // Add order from a paypal Checkout (Paypal takes care of the rest)
            case "PAYPAL":
//                return "MADE IT PAYPAL";
            break;
        }		
	}
		
/**
 * This function converts a cart into an order and sets the appropriate customer id to the order
 * 
 * @param		sessionid	=	Session ID of the user attempting to check out
 * 
 * @return The Header ID (MySQL) of the order that was inserted
 **/
	private function convertToOrder($sessionid){
        // This is the entire header record from the cart in $hid[0] -> $hid[23]
		$flds = 'id, itemsincart, subtotal, fname, lname, addr1, addr2, city, state, zip, phone_1, phone_2, ext_1, ext_2, fax, company, shipfname, shiplname, shipaddr1, shipaddr2, shipcity, shipstate, shipzip, shipphone, shipext, shipcompany';
		$result = $this->db->sel($this->config['fpx'], 'cart_header', $flds, 'session_id="' . $sessionid . '"');
        $hedr=$result[0];
		
        // $cust['internalKey'] is the internalKey of the modx user with the sessionid that was passed in, it should be linked to the customer's orders so
        // that their orders will properly show up in the customer account viewer.
        $result = $this->db->sel($this->config['pfx'], 'web_user_attributes', 'internalKey', 'sessionid="' . $sessionid . '"');
        $cust=$result[0];
		
        // Get Shipping and Handling for order
        $tshp = $this->getShip($sessionid);
        $thnd = $this->getHandle($sessionid);
        $rate = floatval($this->config['tax_percentage']);
        $ttax = $this->getTax($sessionid, $rate);
        $totl = $this->gettotal($sessionid, $rate);
		
		// Generate Date for created entry
        $dat = date("D M j G:i:s T Y");
	    // Copy Cart to an Order
		$tbl = 'order_header';
		$flds = 'cust_id, totshipping, tothandling, tax, total, subtotal, status, orderitems, created, fname, lname, addr1, addr2, city, state, zip, phone_1, phone_2, ext_1, ext_2, fax, company, shipfname, shiplname, shipaddr1, shipaddr2, shipcity, shipstate, shipzip, shipphone, shipext, shipcompany';
		
		// Headerline information
		if ($cust['internalKey'] == ''){
			$c = 0;	
		} else {
			$c = $cust['internalKey'];	
		}
		$headerline = $c . ', ' . $tshp . ', ' . $thnd . ', ' . $ttax . ', ' . $totl . ', ' . $hedr['subtotal'] . ',"NEW" , ' . $hedr['itemsincart'] . ', "' . $dat . '", ';
		
		// Billing Info
		$billingline = '"' . $hedr['fname'] . '", "' . $hedr['lname'] . '", "' . $hedr['addr1'] . '", "' . $hedr['addr2'] . '", "' . $hedr['city'] . '", "' . $hedr['state'] . '", "' . $hedr['zip'] . '", "' . $hedr['phone_1'] . '", "' . $hedr['phone_2'] . '", "' . $hedr['ext_1'] . '", "' . $hedr['ext_2'] . '", "' . $hedr['fax'] . '", "' . $hedr['company'] . '", ';
		
		// Shipping Info
		$shippingline = '"' . $hedr['shipfname'] . '", "' . $hedr['shiplname'] . '", "' . $hedr['shipaddr1'] . '", "' . $hedr['shipaddr2'] . '", "' . $hedr['shipcity'] . '", "' . $hedr['shipstate'] . '", "' . $hedr['shipzip'] . '", "' . $hedr['shipphone'] . '", "' . $hedr['shipext'] . '", "' . $hedr['shipcompany'] . '"';

		// Add Header
		$this->db->ins($this->config['fpx'], 'order_header', $flds, $headerline . $billingline . $shippingline);
		
		// Get Header ID
		$result = $this->db->sel($this->config['fpx'], 'order_header', 'id', 'created="' . $dat . '" AND cust_id=' . $c);
		$headid = $result[0];
		
		// Get Items from the cart to copy into the order
		$result = $this->db->sel($this->config['fpx'], 'cart_detail', 'item_id, quantity, options, optionsprice, totalprice', 'header_id=' . $hedr['id']);
		$cartitems = $result;
		
		// Transfer Items from cart to the order
		for ($i=0; $i < sizeof($cartitems); $i++){
			$row = $result[$i];
			$this->db->ins($this->config['fpx'], 'order_detail', 'item_id, order_id, quantity, options, optionsprice, totalprice', $row['item_id'] . ', ' . $headid['id'] . ', ' . $row['quantity'] . ', "' . $row['options'] . '", ' . $row['optionsprice'] . ', ' . $row['totalprice']);
		}
		
		// Delete cart detail
		$this->db->del($this->config['fpx'], 'cart_detail' , 'header_id=' . $hedr['id']);
		
		// Delete cart header
		$this->db->del($this->config['fpx'], 'cart_header', 'id=' . $hedr['id']);
		
		// Return order header id
		return $headid['id'];
	}
		
/**
 * There are too many parameters to list (and most are obvious)
 *
 * The reason that I didn't just create my own login system is because I figure that most modx users
 * who have an existing website, most likely have existing users.  Thus I don't want to make them
 * switch to a new authentication mechanism.  The other nice thing is that the ModX module already
 * takes care of the login process fairly well, so I didn't see a need to rewrite it.  However, it
 * only takes in fields which would be associated with posting to a forum or blog...whereas ecommerce
 * often requires other fields to be stored for customer accounts (ie: an exact address rather than
 * just a country).  So my module piggy-backs on the existing one.  I first create the modx user
 * and then I create my kiwee_customers entry to store additional data. 
 *
 * @return The id of the user account I just created (if needed by the caller)
 **/
	public function createUserAccount($sessionid, $email, $fname, $lname, $addr1, $addr2, $city, $state, $zip, $country, $phone, $ext, $fax, $company, $username, $password){
        // Create fullname
        $fullname = $fname . ' ' . $lname;
        // Create User Account
        $this->db->ins($this->config['pfx'], 'web_users', 'username, password' . ', "' . $username . '", "' . $password . '"');
	
        $result = $this->db->sel($this->config['pfx'], 'web_users', 'id', 'username="' . $username . '" AND password="' . $password . '"');
        $row = $result[0];
        $id=$row['id'];
		
        $this->db->ins($this->config['pfx'], 'web_user_attributes', 'internalKey, fullname, email, zip, state, country', $id . ', "' . $fullname . '", "' . $email . '", "' . $zip . '", "' .$state . '", "' . $country . '"');
		
		$this->db->ins($this->config['fpx'], 'customers', 'fname, lname, addr1, addr2, city, state, zip, country, phone_1, ext_1, fax, companyname, custid', '"' . $fname . '", "' . $lname . '", "' . $addr1 . '", "' . $addr2 . '", "' . $city . '", "' . $state . '", "' . $zip . '", "' . $country . '", "' . $phone . '", "' . $ext . '", "' . $fax . '", "' . $company . '", ' . $id);
		
		return $id;
	}
		
/**
 * This function will process a credit card transaction through the appropriate gateway
 * 
 * @param 		cc	=	Array of credit card information
 **/
		
	private function processCC($cc){
		$live = isset($this->config['authorize_live']) ? $this->config['authorize_live'] : 'FALSE';
		if ($live=='FALSE'){
			$resp['approval']='APPROVED';
			$resp['gway'] = 'authorizeNET';
			$random='';
   	     	for ($i=0; $i < 12; $i++){
		        $random .= rand(0,9);
   	     	}
   	     	for ($i=0; $i < 6; $i++){
   	         	$random2 .= rand(0,9);
   	     	}
   	     	$resp['authcode'] = $random;
   	     	$resp['trxnid'] = $random2;		
		} else {
			$resp = $this->authorizeDotNetCheckout($cc);	
		}
		
		return $resp;
	}
		
/**
 * This function is designed to tell us how many items are in a particular users cart.
 * 
 * @param 	sessionid		=	The customer's session ID
 **/
	public function getItemCount($sessionid){
		$result = $this->db->sel($this->config['fpx'], 'cart_header', 'itemsincart', 'session_id="' . $sessionid . '"');
		$numitems = $result[0];
		
		return $numitems['itemsincart'];
	}
				
/**
 * This returns the fullname of the item stored in the database
 * 
 * @param	itemid	=	The MySQL id of the item in the database
 * 
 * @return full name of the item from the database
 **/
	public function getFullName($itemid){
		$result = $this->db->sel($this->config['fpx'], 'items', 'fullname', 'id=' . $itemid);
		$row = $result[0];
		
		return $row['fullname'];
	}
		
/**
 * This returns the description of the item from the database
 * 
 * @param 	itemid	=	The MySQL id of the item in the database
 * 
 * @return 	description of the item from the database
 **/
	public function getDescription($itemid){
		$result = $this->db->sel($this->config['fpx'], 'items', 'description', 'id=' . $itemid);
		$row = $result[0];
		
		return $row['description'];
	}
	
/**
 * This function returns the short name of the item from the database
 * 
 * @param 	itemid		= The MySQL id of the item in the database
 * 
 * @return 	name of the item from the database
 **/
		
	public function getName($itemid){
		$result = $this->db->sel($this->config['fpx'], 'items', 'name', 'id=' . $itemid);
		$row = $result[0];
		
		return $row['name'];
	}
		
/**
 * This function returns the price of the item from the database
 * 
 * @param	itemid		=	the MySQL id of the item in the database
 * 
 * @return 	numberformat value of the price from the database for the item
 **/
	public function getPrice($itemid){
		$result = $this->db->sel($this->config['fpx'], 'items', 'amount', 'id=' . $itemid);
		$row = $result[0];
		return number_format($row['amount'], 2);
	}
		
/**
 * This returns a customer's subtotal
 * 
 * @param	sessionid	=	Session ID of the customer
 * 
 * @return	the subtotal in numberformat with 2 decimal places
 **/
	public function getSubtotal($sessionid){
		$result = $this->db->sel($this->config['fpx'], 'cart_header', 'subtotal', 'session_id="' . $sessionid . '"');
		$row = $result[0];
		
		return number_format($row['subtotal'], 2);
	}
		
/**
 * This returns a customer's grand total.
 * 
 * @param 	sessionid	=	Session ID of the customer
 * 
 * @return 	grand total of the customer's order
 **/
	public function getTotal($sessionid){
		//$result = $this->db->sel($this->config['fpx'], 'cart_header', 'subtotal', 'session_id="' . $sessionid . '"');
		//$row = $result[0];
		$subt = $this->getSubtotal($sessionid);//floatval($row['subtotal']);
		$tax = $this->getTax($sessionid);
		$ship = $this->getShip($sessionid);
		$handle = $this->getHandle($sessionid);
		
		return $subt + $tax + $ship + $handle;
	}
		
/**
 * This returns the shipping cost for the customer's cart
 * 
 * @param	sessionid	=	Session ID of the customer
 * 
 * @return 	shipping cost of the customer's order
 * 
 * TODO: Implement a shipping gateway
 **/
	public function getShip($sessionid){
		$shipcost = 5.00;
		return number_format($shipcost, 2);
	}
		
/**
 * This returns the handling cost of the customer's cart
 * 
 * @param 	sessionid	=	Session ID of the customer
 * 
 * @return	handling cost of the customer's order
 **/
	public function getHandle($sessionid){
		$subtotal = $this->getSubtotal($sessionid);
		$handling = 0;
		
		if ($subtotal <= $this->config['handling_threshold']){
			$handling = floatval($this->config['handling_amount']);
		}

		return number_format($handling, 2);
	}
		
/**
 * Returns the taxable and non-taxable subtotals on a customer's order
 * 
 * @param	sessionid	=	Session ID of the customer
 * 
 * @return	array	0-taxable, 1-nontaxable
 **/
	public function calcSubtotals($sessionid) {
		
	}
	
/**
 * This returns the tax on a customer's order
 * 
 * @param	sessionid	=	Session ID of the customer
 * 
 * @return	Taxes on the order
 **/
	public function getTax($sessionid){
		$subtotal = $this->getSubtotal($sessionid);
		$taxpercent = floatval($this->config['tax_percentage']);
		
		if ($this->config['tax_enabled']=='ENABLED'){
			$taxes = $subtotal * $taxpercent;
		} else {
			$taxes = 0;
		}

		return number_format($taxes, 2);
	}
	
/**
 * This method is designed to provide a checkout button.
 * 
 * @return	= 	The code to produce a checkout button for the shopping cart -> payment information
 **/
	public function closeFormCheckout(){
		if ($this->config['cart_forcelogin'] == 'ENABLED'){
	        $button =  "<input class=\"itema_checkoutbutton\" type=\"submit\" value=\"Proceed to Checkout\" name=\"proceedtocheck\" onClick=\"checklogin();\" alt=\"Proceed to Login / Address \">";
		} else {
	        $button =  "<input class=\"itema_checkoutbutton\" type=\"submit\" value=\"Proceed to Checkout\" name=\"proceedtocheck\" onClick=\"gotoLogin();\" alt=\"Proceed to Login / Address \">";
		}
        return $button;
    }

/**
 * This method will provide the opening lines for a basic item form
 * 
 * @param 	name	=	Name of the form
 * @param 	itemid	=	mySQL id of the item who's form we are rendering
 * @param	action	=	The page to call when the form is sent
 * 
 * @return the code to open up a form
 **/
	public function openFormPHP($name, $itemid, $action){
        $open  = '<form name="' . $name . '" id="' . $name . '" method="POST" action="' . $act . '">' . "\n";
        return $open;		
	}
		
/**
 * This will create a basic form close with a submit button
 * 
 * @return	This will create an add to cart button that uses a PHP POST to submit
 **/
	public function closeFormPHP(){
		if ($this->config['cart_enabled'] == 'ENABLED'){
			$button  = '<input type="image" src="http://images.paypal.com/en_US/i/btn/x-click-but22.gif" border="0" name="submit" width="87" height="23" alt="Add to Cart!">';
			$button .= "\n</form>";
		
			return $button;
		} else {
			echo '<p>Contact Us for more information</p>';
			return "\n</form>";	
		}
	}
		
/**
 * This will create an open form chunk of HTML (for javascript add to cart systems)
 * 
 * @return	this will return the code to open a javascript form for adding items to a cart
 **/
	public function openFormJS(){
		$form  = '<form id="' . $id . '" method="POST" action="javascript: get(document.getElementById("' . $id . '"))" />';
		
		return $form;
	}
		
/**
 * This will create a button to add the item to the cart using AJAX via an XMLHttpRequest
 * 
 * @return	this will return a button that performs a javascript add to cart procedure instead of a postback page
 **/
	public function closeFormJS(){
		if ($this->config['cart_enabled'] == 'ENABLED'){
	        $button  = '<input type="hidden" id="item_id" name="item_id" value="[*ProductNumber*]" />' . "\n";
		    $button .= '<input type="hidden" id="sessionid" name="sessionid" value="' . session_id() . '">' . "\n";
        	$button .= '<input type="image" src="http://images.paypal.com/en_US/i/btn/x-click-but22.gif" border="0" name="submit" onclick="additemtocart();" width="87" height="23" alt="Add to Cart!">' . "\n";
        	$button .= '</form>';

        	return $button;
		} else {
			echo '<p>Contact Us for more information</p>';	
			echo '</form>';
		}
	}
		
/**
 * This will create a form button for returning to the catalog page you came from after adding an item to your cart
 * 
 * @return	The code to produce the button mentioned above
 **/
	public function closeFormReturnButton(){
		$button = '<input class="itema_checkoutbutton" type="submit" value="Continue Shopping" name="returntoshop" alt="Return to Shopping">';
		
		return $button;
	}
		
/**
 * This will create a form button which will bring the user to a form where they enter or check their stored billing / shipping addresses
 * 
 * @return	The code to produce a button to continue in the checkout process
 **/
	public function closeFormVerifyCheckout(){
		$button = '<input class="itema_checkoutbutton" type="submit" value="Verify" name="proceedtocheck" onClick="checkshipandbill();" alt="Verify for Checkout">';
		
		return $button;
	}
		
/**
 * This will create a form button which will validate the shipping / billing information and then continue to the next step in the process via javascript
 * 
 * @return	The code to produce a button which verifies the user-entered billing / shipping information
 **/
	public function closeFormSignupForm(){
		$button = '<input class="itema_checkoutbutton" type="submit" value="Signup" name="signupbutton" onMouseOver="checkusername();checkemail();" onClick="checksignup();" alt="Signup">';
		
		return $button;
	}
		
/**
 * This will create a form button which will process the final checkout screen
 * 
 * @return	The code to produce a button which processes the final checkout screen
 **/
	public function closeFormProcessCheckout(){
		$button = '<input class="itema_checkoutbutton" type="submit" value="Process Checkout" name="processcheckout" alt="Process Checkout">';
		
		return $button;
	}
		
/**
 * This will add a new item to the ModX content page database (site_content)
 * 
 * @param       pagetitle     =   Title of the page
 * @param       longtitle     =   Long title of the page
 * @param       description   =   Description of the page
 * @param       published     =   Boolean 1 Published / 0 Not
 * @param       parent        =   Integer FK relationship to parent document 49 for us
 * @param       richtext      =   Boolean 1 RT Editor / 0 Plain
 * @param       template      =   Integer FK relationship to template 7 for product template
 * @param       searchable    =   Boolean 1 Searchable / 0 Not
 * @param       cacheable     =   Boolean 1 Cacheable / 0 Not
 * @param       menutitle     =   Title to show in the menu 
 * 
 * @param	The MySQL ID of the content page that was just added to the database
 **/
	private function addContainer($item_id, $sku, $content, $pagetitle, $longtitle, $description, $published, $parent, $richtext, $template, $searchable, $cacheable, $menutitle){
        $cont = $content;
        $timeraw=time();
		
		$this->db->ins($this->config['pfx'], 'site_content', 'type, contentType, pagetitle, longtitle, description, published, parent, richtext, template, searchable, cacheable, createdby, createdon, content, menutitle', '"document", "text/html", "' . $pagetitle . '", "' . $longtitle . '", "' . $description .'", ' . $published . ', ' . $parent . ', ' . $richtext . ', ' . $template . ', ' . $searchable . ', ' . $cacheable . ', 1, ' . $timeraw . ', "' . $cont . '", "' . $menutitle . '"');

        $result = $this->db->sel($this->config['pfx'], 'site_content', 'id', 'pagetitle="' . $pagetitle . '" AND longtitle="' . $longtitle . '" AND createdon=' . $timeraw);;
        $row = $result[0];

        $this->db->ins($this->config['pfx'], 'site_tmplvar_contentvalues', 'tmplvarid, contentid, value', '4508, ' . $row['id'] . ', "' . $sku . '"');
		
        return $row['id'];		
	}
		
/**
 * This is used to write an item to the database.  This might be utilized by external applications to produce a record in 
 * catalog (or update / delete) an existing record.
 * 
 *  @param      num                 =   Item Number
 *  @param      name                =   Item Name
 *  @param      amt                 =   Item Cost
 *  @param      hazmat              =   Hazardous Materials Add'l Shipping Cost
 *  @param      oversized           =   Oversized Item Shipping Cost
 *  @param      shoppingenabled     =   BOOL 1=SHOP ENABLED 0=SHOP DISABLED
 *  @param      quoteenabled        =   BOOL 1=QUOTE ENABLED 0=QUOTE DISABLED
 *  @param      disabled            =   OPP OF THE VAR I TAKE IN THE PARENT METHOD...$active=0 --> $disabled=1
 *  @param      type                =   Trans Type
 * 
 * @return 	The MySQL ID of the item that was added to the database
 **/
	public function writeItemToDB($num, $name, $shortdescription, $amt, $hazmat, $oversized, $shoppingenabled, $quoteenabled, $disabled, $type){
        if ($type=='NEW'){
            $this->db->ins($this->config['fpx'], 'items', 'name, amount, hazmat, oversized, shoppingenabled, quoteenabled, disabled', '"' . $name . '", ' . $amt . ', ' . $hazmat . ', ' . $oversized . ', ' . $shoppingenabled . ', ' . $quoteenabled . ', ' . $disabled);
        } else if ($type=='UPDATED'){
            $result = $this->db->sel($this->config['fpx'], 'items_audit', 'items_id', 'id=' . $num); 
            $row = $result[0];
			
			$this->db->upd($this->config['fpx'], 'items', 'name="' . $name . '", amount=' . $amt . ', description="' . $shortdescription . '", hazmat=' . $hazmat . ', oversized=' . $oversized . ', shoppingenabled=' . $shoppingenabled . ', quoteenabled=' . $quoteenabled . ', disabled=' . $disabled, 'id=' . $row['items_id']);
        } else if ($type=='DELETE'){
            $this->db->upd($this->config['fpx'], 'items', 'disable=1', 'id=' . $num);
        }
		
        if ($type=='NEW'){
            $result = $this->db->sel($this->config['fpx'], 'items', 'id', 'name="' . $name . '"');
            $row = $result[0];
            $itemid = $row['id'];
			
            $this->db->ins($this->config['fpx'], 'items_audit', 'items_id, sku, name, description, amount, hazmat, oversized, disabled, shoppingenabled, quoteenabled, status', $itemid . ', ' . $itemid . ', "' . $name . '", "' . $shortdescription . '", ' . $amt . ', ' . $hazmat . ', ' . $oversized . ', ' . $disabled . ', ' . $shoppingenabled . ', ' . $quoteenabled . ', "NEW"');
        } else if ($type=='UPDATED'){
            $result = $this->db->sel($this->config['fpx'], 'items', 'id', 'name="' . $name . '"');
            $row = $result[0];
            $itemid = $row['id'];
            $this->db->upd($this->config['fpx'], 'items_audit', 'name="' . $name . '", description="' . $shortdescription . '", amount=' . $amt . ', hazmat=' . $hazmat . ', oversized=' . $oversized . ', disabled=' . $disabled . ', shoppingenabled=' . $shoppingenabled . ', quoteenabled=' . $quoteenabled . ', status="UPDATED"', 'id=' . $num);
	    }																					
		return $itemid;
	}
	
/**
 * This function will return in <option></option> format the list 
 * of configured payment types during customer checkout
 * 
 * @return	Returns the available payment types in <option></option> tags
 * 
 **/
	public function paymentTypes(){
		$result = $this->db->sel($this->config['fpx'], 'config_values', 'optval', 'optname="authorize_enabled"');
		$gway1 = $result[0];
		
		$result = $this->db->sel($this->config['fpx'], 'config_values', 'optval', 'optname="google_enabled"');
		$gway2 = $result[0];

		$result = $this->db->sel($this->config['fpx'], 'config_values', 'optval', 'optname="paypal_enabled"');
		$gway3 = $result[0];

		$gtways = '';
		if ($gway1['optval'] == 'ENABLED'){
			$gtways.= "\n\t<option value=\"CC\">Credit Card via Authorize.net</option>\n";
		}
		if ($gway2['optval'] == 'ENABLED'){
			$gtways.="\t<option value=\"GOOG\">Google Checkout</option>\n";
		}
		if ($gway3['optval'] == 'ENABLED'){
			$gtways.="\t<option value=\"PAYPAL\">Paypal</option>\n";
		}
		return $gtways;				   
	}
		
/**
 * This function implements the Authorize.NET payment gateway
 * 
 * @param	custarr	=	Array of customer information
 * @param	cc		=	Array of credit card information
 * @param	amount	=	Amount to charge to the customer's credit card
 * 
 * NOTE:  When j is greater than 69, the fields are custom fields which
 * 		  can be defined by the merchant.
 * 
 * @return	Response array containing authorization information and status.
 **/
	private function authorizeDotNetCheckout($custarr, $cc, $amount){
        $DEBUGGING                  = 1;
        $TESTING                    = 1;
        $ERROR_RETRIES              = 2;
	
        $auth_net_login_id          = $this->config['authorize_user'];  
        $auth_net_tran_key          = $this->config['authorize_trxnkey']; 
        $auth_net_url               = $this->config['authorize_url'];
        $authnet_values             = array
		  ( "x_login"               => $auth_net_login_id,
            "x_version"             => '3.1',
            "x_delim_char"          => '|',
            "x_delim_data"          => 'TRUE',
            "x_url"                 => 'FALSE',
            "x_type"                => 'AUTH_CAPTURE',
            "x_method"              => 'CC',
            "x_tran_key"            => $auth_net_tran_key,
            "x_relay_response"      => 'FALSE',
            "x_card_num"            => $cc['cardnum'],
            "x_exp_date"            => $cc['expdate'],
            "x_description"         => $this->config['company_name'],
            "x_amount"              => $amount,
            "x_first_name"          => $custarr['fname'],
            "x_last_name"           => $custarr['lname'],
            "x_address"             => $custarr['address'],
            "x_city"                => $custarr['city'],
            "x_state"               => $custarr['state'],
            "x_zip"                 => $custarr['zip'],);
		
		$feilds = '';
		
        foreach( $authnet_values as $key => $value ) $fields .= "$key=" . urlencode( $value ) . "&";
            $ch = curl_init($this->config['authorize_url']);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, rtrim( $fields, "& " ));
            //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
            $resp = curl_exec($ch);
            curl_close ($ch);
            $text = $resp;
            $h = substr_count($text, "|");
            $h++;
            $returnresp['gway']=1;
            $returnresp['approval']='APPROVED';
            for($j=1; $j <= $h; $j++){
				$p = strpos($text, "|");
				
				if ($p === false) {
	                if($j>=69){
                    }else{
                    }
                } else {
 					$p++;
                    $pstr = substr($text, 0 , $p);
														   
                    $pstr_trimmed = substr($pstr, 0, -1);
															   
                    if($pstr_trimmed==''){
						$pstr_trimmed='NO VALUE RETURNED';
	                }
	
                    switch($j){
                        case 1:
                            if($pstr_trimmed=="1"){
	                            $returnresp['approval']='APPROVED';
                            }elseif($pstr_trimmed=="2"){
								$returnresp['approval']='DECLINED';
                            }elseif($pstr_trimmed=="3"){
                                $returnresp['approval']='ERROR';																				                            }
                        break;
						
                        case 5:
                            $returnresp['authcode']=$pstr_trimmed;
                        break;
						
                        case 7:
                            $returnresp['trxnid']=$pstr_trimmed;
                        break;
						
                        default:						
                            if($j>=69){
                            }
                            else{
                            }
                        break;
                    }
                }
           }
        return $returnresp;
	}
		
/**
 * This function is designed to create the hidden fields required for a POST back google checkout.  When a customer
 * chooses google during the checkout process, this will generate a button with the appropriate merchant ID, tax rate, etc.
 * 
 * @param	sessionid	=	Session ID of the user
 * 
 * Note...to implement this correctly, you need to have a web service with 128bit TLS encryption running to receive
 * a notification callback from Google.  This is basically an XML parser that listens for the response, most likely
 * SOAP.  I will implement one for ITema when we have a certificate to sign our server with, but for now, you'll have
 * to go ensure that the payment was processed. 
 **/
	public function googleCheckout($sessionid){
        $merchantid = $this->config['google_merchantid'];
        $webserver = $this->config['google_url'];
        $shipmethod = "UPS Ground";
        $shipprice = $this->getShip($sessionid) + $this->getHandle($sessionid);
        $taxrt = floatval($this->config['tax_percentage']);
        $taxstate = $this->config['tax_state'];

        echo '<form method="POST" action="https://' . $webserver. '/checkout/cws/v2/Merchant/' . $merchantid . '/checkoutForm" accept-charset="utf-8" >' . "\n";
	
        // Go grab the items from the customer's cart
        $result = $this->db->sel($this->config['fpx'], 'cart_header', 'id, fname, lname, addr1, addr2, city, state, zip, cust_id',  'session_id="' . $sessionid . '"');
        $hdr = $result[0];
		
        $result = $this->db->sel($this->config['fpx'], 'cart_detail as B INNER JOIN ' . $this->config['fpx'] . 'items as A ON item_id = A.id', 'A.id, A.name, A.description, quantity, options, optionsprice, totalprice', 'header_id=' . $hdr['id']);
	
        for ($i=0; $i < sizeof($result); $i++){
            $row = $result[$i];
            $k = $i + 1;
            echo '<input type="hidden" name="item_name_' . $k .'" value="' . $row['A.name'] . '"/>' . "\n";
            echo '<input type="hidden" name="item_description_' . $k . '" value="' . $row['A.description'] . '<br />Options: ' . $row['quantity'] . '<br />Options Price: ' . $row['options'] . '"/>' . "\n";
            echo '<input type="hidden" name="item_quantity_' . $k . '" value="' . $row['quantity'] . '"/>' . "\n";
            echo '<input type="hidden" name="item_price_' . $k . '" value="' . (floatval($row['totalprice']) / floatval($row['quantity'])) . '"/>' . "\n";
        }

        echo '<input type="hidden" name="ship_method_name_1" value="' . $shipmethod . '"/>' . "\n";
        echo '<input type="hidden" name="ship_method_price_1\" value="' . $shipprice . '"/>' . "\n";
        echo '<input type="hidden" name="tax_rate" value="' . $taxrt . '"/>' . "\n";
        echo '<input type="hidden" name="tax_us_state" value="' . $taxstate . '"/>' . "\n";
		echo '<input type="hidden" name="_charset_" />' . "\n";
        echo '<input type="image" name="Google Checkout" alt="Fast checkout through Google" src="http://"' . $webserver . '/checkout/buttons/checkout.gif?merchant_id=' . $merchantid . '&w=180&h=46&style=trans&variant=text&loc=en_US" height="46" width="180"/>' . "\n";
		
        echo '</form>';																																																							 
	}
		
/**
 * This function is designed to create the hidden fields required for a POST back paypal checkout.  When a person chooses
 * to checkout via paypal, this will auto-generate the button and fields which are required to send to PayPals website.
 * 
 * @param	sessionid		=	Session ID of the user
 * 
 * NOTE:  Like the Google Checkout gateway, a callback gateway (SOAP server) is required to receive a confirmation of payment
 * back from the gateway when the transaction is completed.
 **/
	public function paypalCheckout($sessionid){
        $merchantid = $this->config['paypal_merchantid'];
        $webserver = $this->config['paypal_url'];
        $shipmethod = 'UPS Ground';
        $shipprice = $this->getShip($sessionid);
        $handleprice = $this->getHandle($sessionid);
        $snh = $shipprice + $handleprice;
        $taxrt = $this->config['tax_percentage'];
        $tax = $this->getTax($sessionid);
        $ctry = $this->config['company_country'];
	
        echo '<form method="POST" action="https://' . $webserver. '/cgi-bin/webscr/">';

        echo '<input type="hidden" name="cmd" value="_cart">';
        echo '<input type="hidden" name="upload" value="1">';
        echo '<input type="hidden" name="business" value="' . $merchantid . '">';
        // Go grab the items from the users cart
			
        $result = $this->db->sel($this->config['fpx'], 'cart_header' , 'id, fname, lname, addr1, addr2, city, state, zip, cust_id' , 'session_id="' . $sessionid . '"');
        $hdr = $result[0];

        $result = $this->db->sel($this->config['fpx'], 'cart_detail as B INNER JOIN ' . $this->config['fpx'] . 'items as A on item_id = A.id', 'A.id, A.name, A.description, quantity, options, optionsprice, totalprice', 'header_id=' . $hdr['id']);
		$k=0;
        for ($i=0; $i < sizeof($result); $i++){
            $row = $result[$i];
            $k = $i + 1;
            echo '<input type="hidden" name="item_name_' . $k . '" value="' . $row['name'] . '">';
            echo '<input type="hidden" name="quantity_' . $k . '" value="' . $row['quantity'] . '">';
            echo '<input type="hidden" name="amount_' . $k . '" value="' . (floatval($row['totalprice']) / floatval($row['quantity'])) . '">';
        }

        echo '<input type="hidden" name="tax_cart" value="' . $tax . '">';
        echo '<input type="hidden" name="handling_cart" value="' . $snh . '" />';
        echo '<input type="hidden" name="first_name" value="' . $hdr['fname'] . '" />';
        echo '<input type="hidden" name="last_name" value="' . $hdr['lname'] . '" />';
        echo '<input type="hidden" name="address1" value="' . $hdr['addr1'] . '" />';
        echo '<input type="hidden" name="address2" value="' . $hdr['addr2'] . '" />';
        echo '<input type="hidden" name="city" value="' . $hdr['city']. '" />';
        echo '<input type="hidden" name="state" value="' . $hdr['state'] . '" />';
        echo '<input type="hidden" name="zip" value="' . $hdr['zip'] . '" />';
        echo '<input type="image" name="Paypal Checkout" alt="Fast checkout through Paypal" src="assets/snippets/shoppingCart/paypal_button.gif">';
        echo '</form>';
	}
		
/**
 * This function will create a new option for a particular item.
 * It will also create a CHUNK in modx, that way the option can
 * easily be displayed on the item page or added to a template
 *
 * PREREQ:  The item record must exist and the list for the item's
 *          options should already be created before calling this
 *          method.
 *
 * @param       listid      =   ID of the list which will provide options for
 *                              the item.
 * @param       name        =   Name of the option
 * @param       renderas    =   How to render the option (CHECK, TEXT, TEXTAREA,
 *                              RADIO, MULTI, SELECT)
 * @param       htmlclass   =   CSS class for the option
 * @param       size        =   Size of the field (also used for num of rows for textarea)
 * @param       length      =   Mostly used for storing the number of columns
 * @param       deflt       =   Default option id or text to display
 **/
	public function createOption($listid, $name, $renderas, $htmlclass, $size, $length, $deflt){
        $itemid = 0;
        if ($renderas=='DROP'){
            $renderas='SELECT';
        }
		
		$this->db->ins($this->config['fpx'], 'options', 'item_id, lists_id, name, renderas, htmlclass, size, length, deflt', $itemid . ', ' . $listid . ', "' . $name . '", "' . $renderas . '", "'. $htmlclass . '", ' . floatval($size) . ', ' . floatval($length) . ',"' . $deflt . '"');

        $edit_type = 0;
        $category = 20;
        $cache_type = 0;
        $locked = 0;

        $result = $this->db->sel($this->config['pfx'], 'site_htmlsnippets', 'id', 'name="' . $name . '"');

        if (sizeof($result)==0){
            //echo "NO RESULTS RETURNED, ADDING HTML CHUNK";
					
            $snippet = '[[kiwee? &elem=OPTIONS&optionname=' . $name . ']]';
            $this->db->ins($this->config['pfx'], 'site_htmlsnippets', 'name, editor_type, category, cache_type, snippet, locked', '"' . $name .'", ' . $edit_type . ', ' . $category . ', ' . $cache_type . ', "' . $snippet . '", ' . $locked . '"');
        }		
	}
		
/**
 * This function will update an exisiting option record
 *
 *   PREREQ: The lists of options should already be created before calling this
 *           method.
 *
 * @param       optionid    =   ID of the option to render
 * @param       listid      =   ID of the list which will provide options for
 *                              the item.
 * @param       name        =   Name of the option
 * @param       renderas    =   How to render the option (CHECK, TEXT, TEXTAREA,
 *                              RADIO, MULTI, SELECT)
 * @param       htmlclass   =   CSS class for the option
 * @param       size        =   Size of the field (also used for num of rows for textarea)
 * @param       length      =   Mostly used for storing the number of columns
 * @param       deflt       =   Default option id or text to display
 **/
	public function updateOption($optionid, $listid, $name, $renderas, $htmlclass, $size, $length, $deflt){
		// All other names passed through renderas I take at face value.  Syntax change though for this one.
        if ($renderas=='DROP'){
            $renderas='SELECT';
        }
		$this->db->upd($this->config['fpx'], 'options', 'lists_id=' . $listid . ', name="' . $name . '", renderas="' . $renderas . '", htmlclass="' . $htmlclass . '", size="' . floatval($size) . ", length=" . floatval($length). '", deflt="' . $deflt . '"', 'id=' . $optionid);		
	}

/**
 * This function is designed to delete an option from the database.
 * 
 * @param		id		=	ID of the option to delete
 **/
	public function deleteOption($id){
        $this->db->del ($this->config['fpx'], 'options', 'id=' . $id);		
	}
		
/**
 * This will create a new header for a blank list.  The list is populated by adding rows in the 
 * lists_options table with FK relationships to the lists table.
 * 
 * @param	name		=	Name of the list
 * @param	description	=	Description of the list
 * 
 * @return	MySQL ID of the list that was created
 **/
    public function createList($name, $description){
        $this->db->ins($this->config['fpx'], 'lists', 'name, description', '"' . $name . '", "' . $description . '"');

        $result = $this->db->sel($this->config['fpx'], 'lists', 'id', 'name="' . $name . '"');
        $row = $result[0];

        return $row['id'];
    }
		
/**
 * This method is designed to update the properties of a list
 * 
 * @param	id			=	ID of the list from MySQL
 * @param	name		=	Updated name of the list
 * @param	description	=	Updated description of the list	
 **/
	public function updateList($id, $name, $description){
		$this->db->upd($this->config['fpx'], 'lists', 'name="' . $name . '", description="' . $description . '"', 'id=' . $id);
	}
		
/**
 * This function is designed to update a list options
 * 
 * @param	id		=	ID of the list option
 * @param	name	=	Name of the list option
 * @param	value	=	Value of the list option
 * @param	offset	=	Price Offset of the list option
 **/
	public function deleteList($id){
        $this->db->del($this->config['fpx'], 'lists_options', 'lists_id=' . $id);
        $this->db->del($this->config['fpx'], 'lists', 'id=' . $id);
	}
		
/**
 * This will get the PK ID's of all options that are to be displayed for a
 * particular item.  This will return an associative indexed array.
 * 
 * @param		itemid	=	This is the itemid of the item for which we want to
 * 							obtain options.
 * 
 * @return	Associative array of all of the options for a particular item
 **/
	public function getAllOptions($itemid){
		$result = $this->db->sel($this->config['fpx'], 'options', 'lists_id, name, renderas, htmlclass, size, length, deflt', 'item_id=' . $itemid);
        for ($i=0; $i < sizeof($result); $i++){
			$row = $result[$i];
            $opts[$i]['lists_id'] = $row['lists_id'];
            $opts[$i]['name'] = $row['name'];
            $opts[$i]['renderas'] = $row['renderas'];
            $opts[$i]['htmlclass'] = $row['htmlclass'];
            $opts[$i]['size'] = $row['size'];
            $opts[$i]['length'] = $row['length'];
            $opts[$i]['default'] = $row['deflt'];
        }

        return $opts;		
	}
	
/**
 * This will return an option with a particular
 *
 * @param       name    =   The name of the option to retrieve
 **/
    function getoption($item_id){
		$result = $this->db->sel($this->config['fpx'], 'options', 'lists_id, name, renderas, htmlclass, size, length, deflt', 'id=' . $item_id);
		$row = $result[0];
		
        $opts['listid'] = $row['lists_id'];
        $opts['name'] = $row['name'];
        $opts['renderas'] = $row['renderas'];
        $opts['htmlclass'] = $row['htmlclass'];
        $opts['size'] = $row['size'];
        $opts['length'] = $row['length'];
        $opts['default'] = $row['deflt'];
		
        return $opts;
	}

/**
 * This will return the option with the specified name
 * 
 * @param	name	=	The name of the option to retrieve
 * 
 * @return	An array with the properties for the option which
 * 			was retrieved from the database.
 **/
	public function getOptionByName($name){
		$result = $this->db->sel($this->config['fpx'], 'options', 'lists_id, renderas, htmlclass, size, maxlen, rows, cols, deflt' , 'name="' . $name . '"');
        $row = $result[0];
        $opts['listid'] = $row['lists_id'];
        $opts['renderas'] = $row['renderas'];
        $opts['htmlclass'] = $row['htmlclass'];
        $opts['size'] = $row['size'];
        $opts['maxlen'] = $row['maxlen'];
		$opts['rows'] = $row['rows'];
		$opts['cols'] = $row['cols'];
        $opts['default'] = $row['deflt'];
 
		return $opts;		
	}
		
/**
 * This method is for the admin interface.  It is only designed to return the names of all lists.
 * 
 * @return	An associative array with the list ids, names and descriptions
 **/
	public function getAllLists(){
        $result = $this->db->sel($this->config['fpx'], 'lists', 'id, name, description');
		
		for ($i=0; $i < sizeof($result); $i++){
			$row = $result[$i];
            $lists[$i]['id'] = $row['id'];
            $lists[$i]['name'] = $row['name'];
            $lists[$i]['description'] = $row['description'];
        }
        return $lists;		
	}
		
/**
 * This function is designed to return the name and description of a list.
 * 
 * @param	listid		=	The id of the list to retrieve
 * 
 * @return 	The name and description of a list with a given id
 **/
	public function getListProperties($listid){
        $result = $this->db->sel($this->config['fpx'], 'lists', 'name, description' , 'id=' . $listid);
        $row = $result[0];
        $listproperties['name'] = $row['name'];
        $listproperties['description'] = $row['description'];

        return $listproperties;
	}

/**
 * This function is designed to return the name, description and price offset of a given list option.
 * 
 * @param	listoptionid	= The id of the list option to return
 * 
 * @return	The name, description, and price offset of the list option in an array
 **/
	public function getListOptionProperties($listoptionid){
        $result = $this->db->sel($this->config['fpx'], 'lists_options', 'name, value, priceoffset', 'id=' . $listoptionid);
		$row = $result[0];
		
        $opt['name'] = $row['name'];
        $opt['value'] = $row['value'];
        $opt['offset'] = $row['priceoffset'];
		
        return $opt;
	}

/**
 * This function will get all list items in a particular list
 * 
 * @param	listid	=	This is the id of the list for which we want
 * 						to retrieve options.
 * 
 * @param	The id, name, value and price offset for all items on a particular list.
 **/
	public function getListOptions($listid){
        $result = $this->db->sel($this->config['fpx'], 'lists_options', 'id, name, value, priceoffset', 'lists_id=' . $listid);

		$opts = array();
		for ($i=0; $i < sizeof($result); $i++){
			$row = $result[$i];
            $opts[$i]['id'] = $row['id'];
            $opts[$i]['name'] = $row['name'];
            $opts[$i]['value'] = $row['value'];
            $opts[$i]['priceoffset'] = $row['priceoffset'];
        }
 
		return $opts;
	}

/**
 * This function will get all list items for a particular list by the name of the list
 * 
 * @param	name	=	The name of the list
 * 
 * @return	The id, name, value and price offset of the list items for the give list
 **/
	public function getListOptionsByName($name){
        $result = $this->db->sel($this->config['fpx'], 'lists', 'id', 'name="' . $name . '"');
        $row = $result[0];
        $result = $this->db->sel($this->config['fpx'], 'lists_options', 'id, name, value, priceoffset', 'lists_id=' . $row['id']);
		
        for ($i=0; $i < sizeof($result); $i++){
			$row = $result[$i];
            $opts[$i]['id'] = $row['id'];
            $opts[$i]['name'] = $row['name'];
            $opts[$i]['value'] = $row['value'];
            $opts[$i]['priceoffset'] = $row['priceoffset'];
        }

		return $opts;
	}
		
/**
 * This function will retrieve the details of a list item by using it's MySQL ID
 * 
 * @param	id	=	The id of the list item to return
 * 
 * @return	The details for a given list item in an array
 **/
	public function getListOption($id){
        $result = $this->db->sel($this->config['fpx'], 'lists_options', 'name, value, priceoffset', 'id=' . $id);
        $row = $result[0];
		
        $opts['name'] = $row['name'];
        $opts['value'] = $row['value'];
        $opts['priceoffset'] = $row['priceoffset'];

        return $opts;		
	}
		
/**
 * This function is designed to add a list item associated with a given list
 * 
 * @param       listid  =   id of the list to associate with this option
 * @param       name    =   Name of the option to add
 * @param       value   =   Value of the option to add
 * @param       offset  =   Offset of the option to add
 **/
	public function createListOption($listid, $name, $value, $offset){
		$this->db->ins($this->config['fpx'], 'lists_options', 'lists_id, name, value, priceoffset', $listid . ', "' . $name. '", "' . $value . '", "' . $offset . '"');
	}
	
/**
 * This function is designed to update a list option
 * 
 * @param 	id			=	ID of the list option
 * @param	name		=	Name of the list option
 * @param	value		=	Value of the list option
 * @param	offset		=	Price Offset of the list option
 **/
	function updateListOption($id, $name, $value, $offset){
		$offsetfloat = floatval($offset);
		$this->db->upd($this->config['fpx'], 'lists_options', 'name="' . $name . '", value="' . $value . '", priceoffset=' . $offsetfloat, 'id=' . $id);
	}
		
/**
 * This function is designed to delete an item from a specified list
 * 
 * @param	listoptionid	=	The id number of the list item to delete
 **/
	public function deleteListOption($listoptionid){
		$this->db->del($this->config['fpx'], 'lists_options', 'id=' . $listoptionid);;		
	}
		
/**
 * This function is designed to interface with renderOption to produce all of the options
 * associated with an item.
 * 
 * @param	itemid	=	The id of the item to find options for
 * 
 * @return	The div which contains all of the options for an item.
 **/
	public function populateOptionsArea($itemid, $layout){
        $result = $this->db->sel($this->config['fpx'], 'items_options', 'options_id', 'item_id=' . $itemid . ' ORDER BY id');
		
		switch($layout){
			case "vertical":
				for ($i=0; $i<sizeof($result); $i++){
					$row = $result[$i];
       	     		$res = $this->db->sel($this->config['fpx'], 'options', 'name, renderas', 'id=' . $row['options_id']);
            		$rw = $res[0];
            		$hiddenopts .= $rw['name'] . ':' . $rw['renderas'] . '||';
            		$opts .= '<div class="itemoptions" style="float:right; width: 60%; padding-bottom: 5px; padding-top: 5px;">' . $this->renderOption($itemid, $rw['name']) . '</div>';
            		$opts .= '<div class="itemoptionslabel" style="float:left; width: 40%">' . $rw['name'] . ':  </div>';
        		}
			break;
		}
        
		$trimmedopts = substr($hiddenopts, 0, strlen($hiddenopts)-2);
        echo '<input type="hidden" id="itemoptsstr" name="itemoptsstr" value="' . $trimmedopts . '" />';
		
        return $opts;
	}
		
/**
 * This function will produce a quantity field with the correct validation (integer or float)
 * 
 * @param	itemid	=	The id of the item to produce a box for.
 * 
 * @return	input field for the quantity
 **/
	public function displayQuantity($itemid){
		if ($this->config['cart_enabled'] == 'ENABLED'){
			echo '<input type="text" id="qtytoenter" name="qtytoenter" size=5 value="1">';	
		} else {
			echo '<input type="text" id="qtytoenter" name="qtytoenter" size=5 value="" disabled>';	
		}
	}
		
/**
 * This function is designed to render an option when it received the itemid and name
 * of the option.  It allows you to choose from several different HTML entities for
 * display.  IE:  RADIO, SELECT, MULTI, CHECK, TEXTAREA OR TEXT
 * 
 * NOTE:  These are stores in the database header table for the option.
 * 
 * @param	optionname	=	Name of the option to render.
 * @param	itemid		=	The id of the item to get options for
 * 
 * @return 	The HTML code to produce the given HTML render of an option
 **/
	private function renderOption($itemid, $optionname){
        $optioninfo = $this->getOptionByName($optionname);
        $opts = $this->getListOptions($optioninfo['listid']);
        $type = strtolower($optioninfo['renderas']);
		
        if (($type=='radiobutton') || ($type=='radio')){
			if ($this->config['cart_enabled'] == 'DISABLED'){$dis="disabled";}
            for ($i=0; $i < sizeof($opts); $i++){
                if ($opts[$i]['name']==$optioninfo['deflt']){$sel="checked";}
                $opt .= '<input ' . $sel . ' class="' . $optioninfo['htmlclass'] . '" type="radio" id="' . $optionname .  '" name="' . $optionname . '" value="' . $opts[$i]['id'] . '" OnClick="updateprice("' . $optionname . '", "' . $opts[$i]['priceoffset'] . '", "radio");" ' . $dis . '>' . $opts[$i]['name'] .  '  ' . $this->priceOffsetDisplay($opts[$i]['priceoffset']) . '<br />' . "\n";
                $sel='';
            }
        } else if (($type=='dropdown') || ($type=='select') || ($type=='drop')){
			if ($this->config['cart_enabled'] == 'DISABLED'){$dis="disabled";}
            $opt .= '<select id="' . $optionname . '" name="' . $optionname . '" class="' . $optioninfo['htmlclass'] . '">' . "\n";

			for ($i=0; $i < sizeof($opts); $i++){
                if ($opts[$i]['name']==$optioninfo['deflt']){$sel='selected';}
                $opt .= "\t" . '<option ' . $sel . ' class="' . $optionname . '-row-' . $i . '" value="' . $opts[$i]['id']. '" OnClick="document.getElementById("' . $optionname . '").selectedIndex=' . $i . '; updateprice("' . $optionname . '", ' . $opts[$i]['priceoffset'] . ', "drop");" ' . $dis . '>' . $opts[$i]['name'] . '  ' . $this->priceOffsetDisplay($opts[$i]['priceoffset']) . '</option>' . "\n";
                $sel='';
			}
	        $opt .= '</select>' . "\n";						
	    } else if (($type=='multiselect') || ($type=='multi')){
			if ($this->config['cart_enabled'] == 'DISABLED'){$dis="disabled";}
            $opt .= '<select id="' . $optionname . '" name="' . $optionname . '" class="' . $optioninfo['htmlclass'] . '" multiple size=' . $optioninfo['size'] . ">\n";
			
			for ($i=0; $i < sizeof($opts); $i++){
                if ($opts[$i]['name']==$optioninfo['deflt']){$sel='selected';}
	                $opt .= "\t" . '<option ' . $sel. ' id="' . $optionname . '-' . $i . '" value="' . $opts[$i]['id'] . '" OnClick="updateprice("' . $optionname . '", ' . $opts[$i]['priceoffset'] . ', "multi" );" ' . $dis . '>' . $opts[$i]['name'] .  '  ' . $this->priceOffsetDisplay($opts[$i]['priceoffset']) . '</option><br />' . "\n";	                $sel='';
            }
            $opt .= '</select>' . "\n";
        } else if (($type=='checkbox') || ($type=='check')){
			if ($this->config['cart_enabled'] == 'DISABLED'){$dis="disabled";}
			for ($i=0; $i < sizeof($opts); $i++){
	           if ($opts[$i]['name']==$optioninfo['deflt']){$sel='checked';}													
               $opt .= '<input ' . $sel. ' id="' . $optionname . '-' . $i . '" class="' . $optioninfo['htmlclass'] . '" name="' . $optionname . '" type="checkbox" value="' . $opts[$i]['id'] . '" OnClick="updateprice("' . $optionname . '", ' . $opts[$i]['priceoffset'] . ', "check");" ' . $dis . '>' . $opts[$i]['name'] . '  ' . $this->priceOffsetDisplay($opts[$i]['priceoffset']) . '<br />' . "\n";
               $sel='';
           }			
		} else if (($type=='textarea')) {
			if ($this->config['cart_enabled'] == 'DISABLED'){$dis="disabled";}
            $opt .= '<textarea id="' . $optionname . '" class="' . $optioninfo['htmlclass'] . '" name="' . $optionname . '" rows="' . $optioninfo['rows'] . '" cols="' . $optioninfo['cols'] . '" ' . $dis . '>' . "\n";
            $opt .= '</textarea>';
        } else if (($type=='text')){
			if ($this->config['cart_enabled'] == 'DISABLED'){$dis="disabled";}
            $opt .= '<input type="text" id="' . $optionname . '" class="' . $optioninfo['htmlclass'] . '" name="' . $optionname . '" size=' . $optioninfo['size'] . ' maxlength=' . $optioninfo['maxlen'] . ' ' . $dis . '/>' . "\n";
        }

        return $opt;
	}
		
/**
 * This is a helper function to decide whether to display price offset or not;
 * 
 * The reson I broke this method out is so that it could be called in-line
 * when I render the option and so that it can be overridden easily by developers
 * (like the one who is probably reading this)
 * 
 * @param	poffset	=	Price offset
 * 
 * @return price if > zero else nothing
 **/
	private function priceOffsetDisplay($poffset){
        $num = number_format($poffset, 2);
		
        if ($num != 0.00){
            return "&nbsp;&nbsp;" . $num;
        }
	}
		
/**
 * This function is designed to return an associative array of information about a customer, including their ModX user information.
 * 
 * @param	id	=	The MySQL id of the customer in the customers table
 * 
 * @return	The customer information in an array format
 **/
	public function getCustInfo($id){
        $result = $this->db->sel($this->config['fpx'], 'customers', 'fname, lname, addr1, addr2, city, state, zip, phone_1, phone_2, ext_1, ext_2, fax, custid, companyname', 'id=' . $id);
        $row = $result[0];
		
        $cust['id'] = $id;
        $cust['fname'] = $row['fname'];
        $cust['lname'] = $row['lname'];
        $cust['addr1'] = $row['addr1'];
        $cust['addr2'] = $row['addr2'];
        $cust['city'] = $row['city'];
        $cust['state'] = $row['state'];
        $cust['zip'] = $row['zip'];
        $cust['phone_1'] = $row['phone_1'];
        $cust['phone_2'] = $row['phone_2'];
        $cust['ext_1'] = $row['ext_1'];
        $cust['ext_2'] = $row['ext_2'];
        $cust['fax'] = $row['fax'];
        $cust['custid'] = $row['custid'];
        $cust['companyname'] = $row['companyname'];

        $result = $this->db->sel($this->config['pfx'], 'web_users', 'username, password', 'id=' . $row['custid']);
        $row = $result[0];
        $cust['username'] = $row['username'];
        $cust['password'] = $row['password'];

        $result = $this->db->sel($this->config['pfx'], 'web_user_attributes', 'failedlogincount, blocked, blockeduntil, logincount, comment', 'internalKey=' . $cust['custid']);
        $row = $result[0];
        $cust['failedlogincount'] = $row['failedlogincount'];
        $cust['blocked'] = $row['blocked'];
        $cust['blockeduntil'] = $row['blockeduntil'];
        $cust['logincount'] = $row['logincount'];
        $cust['commentssection'] = $row['comment'];

        return $cust;		
	}
		
/**
 * This function is designed to check whether there is a user in the system who is already using the username
 * that a person is trying to use to sign up for an account.
 * 
 * @param	username	=	The username the customer is attempting to use
 * 
 * @return	TRUE if dup is found, FALSE if username is OK
 **/
	public function checkUsername($username){
        $result = $this->db->sel($this->config['pfx'], 'web_users', 'id', 'username="' . $username . '"');

        if (sizeof($result) > 0){
			return 'TRUE';	
		} else {
			return 'FALSE';
		}
	}
		
/**
 * This function is designed to check whether there is a user in the system who already has registered the email address
 * that a person is trying to use to sign up for a new account.
 * 
 * @param	email	=	Email address that the customer is attempting to use
 * 
 * NOTE: TRUE if dup is found, FALSE if email is OK, INVALID if email is not
 *       correctly formatted.
 **/
	public function checkEmail($email){
        $result = $this->db->sel($this->config['pfx'], 'web_user_attributes', 'email', 'email="' . $email . '"');

        if (ereg("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $email)){
			if (sizeof($result) < 0){
				return 'TRUE';	
			} else {
				return 'FALSE';
			}
       	} else {
            return 'INVALID';
        }
	}

/**
 * This function is designed to update customer info stored in a couple tables within ModX
 *
 * @param   id                  =   Customer ID in MOdX Ecommerce
 * @param   intkey              =   Internal ModX ID
 *
 * //SELF EXPLANATORY - BASIC CUST INFO
 * @param   companyname
 * @param   fname
 * @param   lname
 * @param   addr1
 * @param   addr2
 * @param   city
 * @param   state
 * @param   zip
 * @param   phone_1
 * @param   phone_2
 * @param   ext_1
 * @param   ext_2
 * @param   fax
 *
 * @param   username            =   username of the person
 * @param   password            =   hex md5 hash of the new password
 *
 * @param   logincount          =   Number of logins
 * @param   failedlogincount    =   Number of times a user has failed during login (Set this to 0 too to unlock an account)
 * @param   blocked             =   BOOL (0=false || 1=true)
 * @param   blockeduntil        =   TimeStanp of sorts telling when a failed user can log in again (Set to 0 to reset)
 * @param   comment             =   Comment about the customer (Could be anything)
 **/
	public function updateCustInfo($id, $intkey, $companyname, $fname, $lname, $addr1, $addr2, $city, $state, $zip, $phone_1, $phone_2, $ext_1, $ext_2, $fax, $username, $password, $logincount, $failedlogincount, $blocked, $blockeduntil, $comment){
		// Update ITema customer's table
		$this->db->upd($this->config['fpx'], 'customers', 'companyname="' . $companyname . '", fname="' . $fname . '", lname="' . $lname . '", addr1="' . $addr1 . '", addr2="' . $addr2 . '", city="' . $city . '", state="' . $state . '", zip="' . $zip . '", phone_1="' . $phone_1 . '", phone_2="' . $phone_2 . '", ext_1="' . $ext_1 . '", ext_2="' . $ext_2 . '", fax="' . $fax . '"', 'id=' . $id);
		// Update ModX username and password
		$this->db->upd($this->config['pfx'], 'web_users', 'username="' . $username . '", password="' . $password . '"', 'id=' . $intkey);
		// Update OTHER ModX user attributes
		$this->db->upd($this->config['pfx'], 'web_user_attributes', 'logincount=' . $logincount . ', failedlogincount=' . $failedlogincount . ', blocked=' . $blocked . ', blockeduntil=' . $blockeduntil . ', comment="' . $comment . '"', 'internalKey=' . $intkey);
	}
		
/**
 * This is designed to return the details of an order by id
 * 
 * @param	id	=	MySQL id (Order ID)
 * 
 * @return	An array of information about the order retrieved.
 **/
	public function getOrderInfo($id){
        $result = $this->db->sel($this->config['fpx'], 'order_header', 'id, pay_id, cust_id, totshipping, tothandling, tax, total, subtotal, paymentApproved, authCode, ponumber, status, orderitems, created, updated, shipfname, shiplname, shipaddr1, shipaddr2, shipcity, shipstate, shipzip, shipphone, shipext', 'id=' . $id);
        $row = $result[0];

        $ordinfo['id'] = $row['id'];
        $ordinfo['pay_id'] = $row['pay_id'];
        $ordinfo['cust_id'] = $row['cust_id'];
        $ordinfo['totshipping'] = $row['totshipping'];
        $ordinfo['tothandling'] = $row['tothandling'];
        $ordinfo['tax'] = $row['tax'];
        $ordinfo['total'] = $row['total'];
        $ordinfo['subtotal'] = $row['subtotal'];
        $ordinfo['paymentApproved'] = $row['paymentApproved'];
        $ordinfo['authCode'] = $row['authCode'];
        $ordinfo['ponumber'] = $row['ponumber'];
        $ordinfo['status'] = $row['status'];
        $ordinfo['orderitems'] = $row['orderitems'];
        $ordinfo['created'] = $row['created'];
        $ordinfo['updated'] = $row['updated'];
        $ordinfo['shipfname'] = $row['shipfname'];
        $ordinfo['shiplname'] = $row['shiplname'];
        $ordinfo['shipaddr1'] = $row['shipaddr1'];
        $ordinfo['shipaddr2'] = $row['shipaddr2'];
        $ordinfo['shipcity'] = $row['shipcity'];
        $ordinfo['shipstate'] = $row['shipstate'];
        $ordinfo['shipzip'] = $row['shipzip'];
        $ordinfo['shipphone'] = $row['shipphone'];
        $ordinfo['shipext'] = $row['shipext'];
        
		$result = $this->db->sel($this->config['fpx'], 'pay_gateways', 'name', 'id=' . $ordinfo['pay_id']);
        $row = $result[0];

        $ordinfo['payment_name'] = $row['name'];
		
        $result = $this->db->sel($this->config['fpx'], 'customers', 'fname, lname, addr1, addr2, city, state, zip, phone_1, ext_1, phone_2, ext_2, fax, companyname, custid', 'id=' . $ordinfo['cust_id']);
        $row = $result[0];
		
        $ordinfo['fname'] = $row['fname'];
        $ordinfo['lname'] = $row['lname'];
        $ordinfo['addr1'] = $row['addr1'];
        $ordinfo['addr2'] = $row['addr2'];
        $ordinfo['city'] = $row['city'];
        $ordinfo['state'] = $row['state'];
        $ordinfo['zip'] = $row['zip'];
        $ordinfo['phone_1'] = $row['phone_1'];
        $ordinfo['ext_1'] = $row['ext_1'];
        $ordinfo['phone_2'] = $row['phone_2'];
        $ordinfo['ext_2'] = $row['ext_2'];
        $ordinfo['fax'] = $row['fax'];
        $ordinfo['companyname'] = $row['companyname'];
        $ordinfo['modxcustid'] = $row['custid'];

        $result = $this->db->sel($this->config['pfx'], 'web_user_attributes', 'email', 'id=' . $ordinfo['modxcustid']);
        $row = $result[0];
        $ordinfo['email'] = $row['email'];

        return $ordinfo;
	}
		
/**
 * This function is designed to return the order statistics for the order maintenance admin page
 * 
 * @return	An array of the order stats information
 **/
	public function getOrderStats(){
        $result = $this->db->sel($this->config['fpx'], 'order_header', 'id, status');

        $ordstat['neworders'] = 0;
        $ordstat['cancelledorders'] = 0;
        $ordstat['updatedorders'] = 0;
        $ordstat['processedorders'] = 0;
        $ordstat['errororders'] = 0;
        $ordstat['backorders'] = 0;
        $ordstat['shippedorders'] = 0;
        $ordstat['totalorders'] = 0;		
		
        for($i=0; $i < sizeof($result); $i++){
			$row = $result[$i];
            switch($row['status']){
                case "NEW":
                    $ordstat['neworders']++;
                break;
				
                case "CANCELLED":
                    $ordstat['cancelledorders']++;
                break;
							
  		        case "UPDATED":
  		            $ordstat['shippedorders']++;
                break;
						
                case "PROCESSING":
                    $ordstat['processedorders']++;
                break;
							
                case "SHIPPED":
                    $ordstat['shippedorders']++;
 	            break;
							
                case "BACKORDERED":
                    $ordstat['backorders']++;
                break;
						
                case "ERROR":
                    $ordstat['errororders']++;
                break;
            }
  	        $ordstat['totalorders']++;
        }
		
		$ordstat['totalorders']--;

        return $ordstat;
	}		
		
/**
 * This function is designed to return an array of item maintenance statistics
 * 
 * @return	An array of item statistics
 **/
	public function getItemStats(){
        $result = $this->db->sel($this->config['fpx'], 'items_audit', 'id, status');

        $itemstat="";

        $itemstat['newitems'] = 0;
        $itemstat['currentitems'] = 0;
        $itemstat['deleteditems'] = 0;
        $itemstat['updateditems'] = 0;
        $itemstat['newitems'] = 0;
        $itemstat['totalitems'] = 0;
		
        for ($i=0; $i < sizeof($result); $i++){
			$row = $result[$i];
            switch($row['status']){
                case "new":
                    $itemstat['newitems']++;
                break;
							
                case "current":
                    $itemstat['currentitems']++;
                break;
									
                case "updated":
                    $itemstat['updateditems']++;
                break;
									
                case "deleted":
                    $itemstat['deleteditems']++;
                break;
			}
			$itemstat['totalitems']++;
		}
        return $itemstat;
	}
		
/**
 * This function will check whether a user is a valid modx user and then make sure that
 * they have an ecomm account.  If they don't have either, false is returned.  If they
 * DO have both, true is returned.  If they don't have an ecomm account, I will make one
 * for them (simple update of modx_ecomm_customers
 *
 * @param   sessionid       =   Session ID of the user
 * @param   webshortname    =   ModX username logged in
 * @param   webinternalkey  =   ModX mySQL ID of the user logged in
 * @param   webemail        =   ModX email of the user logged in
 * @param   webvalid        =   Not sure, but I won't handle it for now.  I believe
 *                              (without research) that it is some form of session var
 *                              to identify the user as being a valid web user.  Perhaps
 *                              reversible encryption?
 * @param   webuser         =   Not sure, but I won't handle it for now.  I believe
 *                              (without research) that it is some form of session var
 *                              to identify the user as being a valid web user.  Perhaps
 *                              this is done with reversible encryption since I don't see
 *                              a translation table of sorts in the modx_ database.
 **/
	public function checkLogin($sessionid, $webshortname, $webinternalkey, $webemail, $webvalid, $webuser){
        // Check for valid data
        if ($webinternalkey!='' && $sessionid!='' && $webshortname!=''){
            $result = $this->db->sel($this->config['pfx'], 'web_users', 'username, password','id=' . $webinternalkey);
            $row = $result[0];

            $dbuser = $row['username'];
            $dbpass = $row['password'];
            // Check that the dbuser matches the clientside username
            if ($dbuser == $webshortname){
                $result = $this->db->sel($this->config['pfx'], 'web_user_attributes', 'email, sessionid, phone, mobilephone, country, state, zip, fax, fullname', 'internalKey=' . $webinternalkey);
                $row = $result[0];

                $email=$row['email'];
                $dbsession = $row['sessionid'];
                $modxphone = $row['phone'];
                $modxmobilephone = $row['mobilephone'];
                $modxcountry = $row['country'];
                $modxstate = $row['state'];
                $modxzip = $row['zip'];
                $modxfax = $row['fax'];
                $modxfullname = $row['fullname'];

                // Check that client email and session info matches what is in the database
                if (($email==$webemail) && ($dbsession==$sessionid)){
                    // OK now we know the client is authenticated for ModX
                    // Lets make sure they have an ecomm account
                    $result = $this->db->sel($this->config['fpx'], 'customers', 'id', 'custid=' . $webinternalkey);
                    if (sizeof($result) > 0){
                        // YAY, the user is in both systems, you may pass...
                        return 'MATCH';
                    } else {
                        // In this case, the user might have existed pre-ecomm days, so
                        // we need to add their record
                        if ($modxcountry==223){
                            $modxcountry='USA';
                        }{
                            $modxcountry='';
                        }// Sorry, everyone else will have to add their own to this
                        $this->db->ins($this->config['fpx'], 'customers', 'fname, state, country, zip, phone_1, phone_2, fax, custid', '"' . $modxfullname . '", "' . $modxstate . '", "' . $modxcountry . '", "' . $modxzip . '", "' . $modxphone . '", "' . $modxmobilephone . '", "' . $modxfax . '", ' . $webinternalkey);
                        return 'MATCH';
                    }

                } else {
                    // client-side email matches a record, but their sessionid doesn't match the db value
                    return 'STALESESSION';
                }
            }else {
                // client-side username didn't match what was in the database
                return 'TRYAGAINORCREATE';
            }
        } else {
            // client-side didn't pass us valid data
            return 'NODATA';
        }
	}
		
/**
 * This function is designed to grab all of the options from the DB but only display
 * those options which are not already in use by the item.
 * 
 * @param	itemid	=	Item ID of the item we are retrieving options for
 **/
	public function getAllItemOptions($itemid){
        $result = $this->db->sel($this->config['fpx'], 'items_options', 'options_id', 'item_id=' . $itemid);

        // Get Chosen Options from DB
        for ($i=0; $i < sizeof($result); $i++){
			$row = $result[$i];
            $chosen[$i]=$row['options_id'];
        }

        $result = $this->db->sel($this->config['fpx'], 'options', 'id, name');
        // Get All Options in DB
        for ($i=0; $i < sizeof($result); $i++){
			$row = $result[$i];
            $all[$i]['id'] = $row['id'];
            $all[$i]['name'] = $row['name'];
        }
		
        // Only display those options which are not chosen
        for ($k=0; $k < $i; $k++){
            $alreadyused='false';
            for($l=0; $l < sizeof($chosen); $l++){
                if ($all[$k]['id']==$chosen[$l]){
                    $alreadyused='true';
                }
            }
            if ($alreadyused=='false'){
                echo '<div id="alloptdiv_' . $all[$k]['id'] .  '" style="color: white; background-color: #1A496D; padding:5px; border-style: solid; border-width: 2px; border-color: #518BFF; margin: 3px; margin-left: 10px; margin-right: 10px;" class="alloptdivs">' . $all[$k]['name'] . '</div>';
            }
        }		
	}

/**
 * This is designed to grab the options already associated with the item
 * 
 * @param	itemid	=	The ID of the item we are retrieving options for
 **/
	public function getAllChosenOptions($itemid){
        $result = $this->db->sel($this->config['fpx'], 'items_options', 'options_id', 'item_id=' . $itemid . ' ORDER BY id');

        for ($i=0; $i < sizeof($result); $i++){
			$row = $result[$i];
            $res = $this->db->sel($this->config['fpx'], 'options', 'id, name', 'id=' . $row['options_id']);
            $row = $res[0];
		
            echo '<div id="alloptdiv_' . $row['id'] . '" style="color: white; background-color: #1A496D; padding:5px; border-style: solid; border-width: 2px; border-color: #518BFF; margin: 3px; margin-left: 10px; margin-right: 10px;" class="alloptdivs">' . $row['name'] . '</div>';
        }
	}

/**
 * This is designed to grab all of the content templates from ModX
 * 
 * @param	tmplid		=	This is the id of the template being used
 * 
 * @return	An HTML dropdown of the templates in the system in the Content Templates
 * 			subcategory.
 **/
	public function getTemplates($tmplid){
		$result = $this->db->sel($this->config['pfx'], 'site_templates', 'templatename, id');
		
		echo '<select tabindex="10" id="templateid" name="templateid" >';
		
		for ($i=0; $i < sizeof($result); $i++){
			$row = $result[$i];
            if ($tmplid==$row['id']){
                $enbl='SELECTED';
            }else {
                $enbl='';
            }
            echo '<option ' . $enbl . ' name="' . $row['templatename'] . '" value="' . $row['id'] . '">' . $row['templatename'] . '</option>';
        }		
        echo '</select>';
	}
		
/**
 * This function is designed to return all chunks from ModX to use for
 * content area templates.
 * 
 * @param	catid	=	The category id, defaults to -1 which means
 * 						don't use the parameter if nothing is passed
 * 						in by the user;
 * 
 * @return	The code to display the chunks as a drop down menu
 **/
	public function getChunks($catid=-1){
		if ($catid==-1){
	        $result = $this->db->sel($this->config['pfx'], 'site_htmlsnippets', 'name, id');
		} else {
            $result = $this->db->sel($this->config['pfx'], 'site_htmlsnippets', 'name, id', 'category=' . $catid);	
		}
		
        echo '<select onchange="updatecontenttemplate();" tabindex="11" id="chunkid" name="chunkid">';
        echo '<option name="Default" value="NONE">Choose Content Template:</option>';
        for($i=0; $i < sizeof($result); $i++){
			$row = $result[$i];
			echo '<option name="chunkid-' . $row['id'] . '" value="' . $row['id'] . '">' . $row['name'] . '</option>';
//            echo '<option name="chunkid-' . $row['id'] . '" value="' . $row['id'] . '/>' . $row['name'] . '</option>';
        }
        echo '</select>';
	}		
		
/**
 * This function is designed to return the value of a chunk (HTML Code)
 * 
 * This is mainly used for the Administrative Interface to choose the content
 * template to use for a product page.
 * 
 * @param	chunkid	=	ID of the chunk to pull from the database.
 * 
 * @return	The content from the chunk with the given id
 **/
	public function getChunkContent($chunkid){
        $result = $this->db->sel($this->config['pfx'], 'site_htmlsnippets', 'snippet', 'id="' . $chunkid . '"');
        $row = $result[0];
        echo $row['snippet'];
	}
		
/**
 * This function is designed to return an array of customer information based on their webInternalKey
 * 
 * @param	webinternalkey	=	Customer's ModX webInternalKey
 * 
 * @return	An array of Customer information
 **/
	public function getCustomerInfo($webinternalkey){
		$result = $this->db->sel($this->config['fpx'], 'customers', 'fname, lname, addr1, addr2, city, state, zip, phone_1, phone_2, ext_1, ext_2, fax, companyname, country', 'custid=' . $webinternalkey);
		$row = $result[0];
		
        $ret['fname'] = $row['fname'];
        $ret['lname'] = $row['lname'];
        $ret['addr1'] = $row['addr1'];
        $ret['addr2'] = $row['addr2'];
        $ret['city'] = $row['city'];
        $ret['state'] = $row['state'];
        $ret['zip'] = $row['zip'];
        $ret['phone_1'] = $row['phone_1'];
        $ret['phone_2'] = $row['phone_2'];
        $ret['ext_1'] = $row['ext_1'];
        $ret['ext_2'] = $row['ext_2'];
        $ret['fax'] = $row['fax'];
        $ret['companyname'] = $row['companyname'];
        $ret['country'] = $row['country'];

        return $ret;		
	}
		
/**
 * This function is designed to create an order header with the details that the user provides.
 * 
 * It updates the fields found in the cart header for billing and shipping information
 * 
 * @param	TOO Many to List:	It takes in the session id and all POST data for billing and 
 *								shipping information
 **/
	public function updateCartForCheckout($sessionid, $emailbilling, $fnamebilling, $lnamebilling, $addr1billing, $addr2billing, $citybilling, $statebilling, $zipbilling, $phonebilling, $extbilling, $faxbilling, $companybilling, $companyship, $fnameship, $lnameship, $addr1ship, $addr2ship, $cityship, $stateship, $zipship, $phoneship, $extship){
        $this->db->upd($this->config['fpx'], 'cart_header', 'fname="' . $fnamebilling . '", lname="' . $lnamebilling . '", addr1="' . $addr1billing . '", addr2="' . $addr2billing . '", city="' . $citybilling . '", state="' . $statebilling . '", zip="' . $zipbilling . '", phone_1="' . $phonebilling . '", ext_1="' . $extbilling . '", fax="' . $faxbilling . '", company="' . $companybilling . '", shipcompany="' . $companyship . '", shipfname="' . $fnameship . '", shiplname="' . $lnameship . '", shipaddr1="' . $addr1ship . '", shipaddr2="' . $addr2ship . '", shipcity="' . $cityship . '", shipstate="' . $stateship . '", shipzip="' . $zipship . '", shipphone="' . $phoneship . '",  shipext="' . $extship . '"', 'session_id="' . $sessionid . '"');
	}
}																																								
